//
// Created by lenovo on 2022/3/10.
//
#include <jni.h>
#include <optional>
#include <string>
#include "AnrCatcher.h"
#include "jnienv/JniEnv.h"
#include "Logging.h"
using namespace std;
using namespace AnrChecker;

static AnrCatcher *sAnrCatcher = nullptr;

/**
 * 用于存储AnrCatcher类的相关信息
 */
struct AnrCatcherInfo {
    jclass anrCatcherCls = nullptr;
    jmethodID anrCallbackId = nullptr;
} anrCather;

/**
 * 执行Java层的ANR回调函数
 * @return 返回true表示执行成功，否则表示执行失败
 */
bool executeAnrCallback() {
    ALOGI("===================executeAnrCallback==================");
    JNIEnv *env = JniEnvManager::getJniEnv();
    ALOGI("===================executeAnrCallback env=%d=================", env != nullptr);
    if (!env) {
        return false;
    }
    ALOGI("===================CallVoidMethod=anrCatcherCls=%d====anrCallbackId=%d=====",
          anrCather.anrCatcherCls != nullptr, anrCather.anrCallbackId != nullptr);
    env->CallStaticVoidMethod(anrCather.anrCatcherCls, anrCather.anrCallbackId);
    return true;
}

void registerNativeAnrSigquit(JNIEnv *env, jclass) {
    ALOGI("===================registerNativeAnrSigquit1==================");
    if (sAnrCatcher) {
        return;
    }
    ALOGI("===================registerNativeAnrSigquit2==================");
    sAnrCatcher = new AnrCatcher;
}

void unregisterNativeAnrSigquit(JNIEnv *env, jclass) {
    delete sAnrCatcher;
}

static const JNINativeMethod ANR_CATCHER_METHODS_MAP[] = {
        {"registerAnrSigquit", "()V", (void *)registerNativeAnrSigquit},
        {"unregisterAnrSigquit", "()V", (void *)unregisterNativeAnrSigquit}
};

int bindAnrCatcherMethods(JNIEnv *env) {
    const char *clsName = "com/utopia/anr/lib/AnrCatcher";
    int nMethods = sizeof(ANR_CATCHER_METHODS_MAP) / sizeof(ANR_CATCHER_METHODS_MAP[0]);
    jclass clsInstance = env->FindClass(clsName);
    if (!clsInstance) {
        return -1;
    }
    ALOGI("===================bindAnrCatcherMethods==================%s", clsName);
    anrCather.anrCatcherCls = reinterpret_cast<jclass>(env->NewGlobalRef(clsInstance));
    anrCather.anrCallbackId = env->GetStaticMethodID(clsInstance, "onAnrReceiving", "()V");
    ALOGI("===================anrCather.anrCallbackId==================%d", anrCather.anrCallbackId != nullptr);
    if (env->RegisterNatives(clsInstance, ANR_CATCHER_METHODS_MAP, nMethods) != JNI_OK) {
        return -1;
    }
    ALOGI("===================bindAnrCatcherMethods==================");
    env->DeleteLocalRef(clsInstance);
    return 0;
}

jint JNI_OnLoad(JavaVM *vm, void *) {
    ALOGI("===================JNI_OnLoad==================");
    JniEnvManager::init(vm);
    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) != JNI_OK) {
        return -1;
    }
    if (bindAnrCatcherMethods(env) != JNI_OK) {
        return -1;
    }
    return JNI_VERSION_1_6;
}